/****************************************************************************************/
/*                                                                     					*/
/*  M16C/62P Group Program Collection                                  					*/
/*                                                                     					*/
/*  FILE NAME : serial.c                           		            					*/
/*  CPU       : This program is the Serial flash boot loader by Xmodem data transfer	*/
/*  HISTORY   : 2006.12.08 Ver 0.01                                    					*/
/*                                                                    	 				*/
/*  Copyright (C) 2006. Renesas Technology Corp.                       					*/
/*  Copyright (C) 2006. Renesas Solutions Corp.                        					*/
/*  All right reserved.                                                					*/
/*                                                                     					*/
/*****************************************************************************************/

/**************************************/
/*    include file                    */
/**************************************/
#include <string.h>
#include "delay_timer.h"
#include "serial.h"

#include "sfr62p.h"

/**************************************/
/*   External reference declaration   */
/**************************************/
extern volatile unsigned char TimerChannelDelayStatus[];

/****************************************/
/*    InitSci function                  */
/****************************************/
void InitSci ( void )
{
    //pclk1 = 1;   /// seleck F1SIO,using default setting
    /* UART Transmit/Receive Control Register 2 */
    ucon = 0x00;
         /*   00000000
          b0    U0IRS       UART0 transmit irq cause select bit, 0 = transmit buffer empty
          b1    U1IRS       UART1 transmit irq cause select bit, 0 = transmit buffer empty
          b2    U0RRM       UART0 continuous receive mode enable bit, set to 0 in UART mode
          b3    U1RRM       UART1 continuous receive mode enable bit, set to 0 in UART mode
          b4    CLKMD0      CLK/CLKS select bit 0, set to 0 in UART mode
          b5    CLKMD1      CLK/CLKS select bit 1, set to 0 in UART mode
          b6    RCSP        Separate CTS/RTS bit,
          b7    Reserved, set to 0 */

    /* UART0 transmit/receive control register 0 */
    /* f1 count source, CTS/RTS disabled, CMOS output */
    u0c0 = 0x10;
         /* 00010000
          b1:b0 CLK01:CLK0  BRG count source select bits                        //01         F8SIO
          b2    CRS         CTS/RTS function select bit
          b3    TXEPT       Transmit register empty flag
          b4    CRD         CTS/RTS disable bit
          b5    NCH         Data output select bit
          b6    CKPOL       CLK polarity select bit,set to 0 in UART mode
          b7    UFORM       Transfer format select bit,set to 0 in UART mode */

    /* set UART0 bit rate generator bit rate can be calculated by:
          bit rate = ((BRG count source / 16)/baud rate) - 1
          Baud rate is based on main crystal or PLL not CPU core clock */
    u0brg = BAUD(115200L);		// set baud rate
	
    /* UART0 transmit/receive control register 1 */
    /*  disable transmit and receive, no error output pin, data not inverted */
    u0c1 = 0x00;
         /*  00000000
          b0    TE          Transmit enable bit
          b1    TI          Transmit buffer empty flag
          b2    RE          Receive enable bit
          b3    RI          Receive complete flag
          b5:b4             Reserved, set to 0
          b6    UOLCH       Data logic select bit
          b7    UOERE       Error signal output enable bit */

    /* UART0 transmit/receive mode register */
    /* 8-bit data,asynch mode, internal clock, 1 stop bit, no parity */
    u0mr = 0x05;
         /*  00000101
          b2:b0 SMD12:SMD1  Serial I/O Mode select bits
          b3    CKDIR       Internal/External clock select bit, CKDIR
          b4    STPS        Stop bit length select bit, STPS
          b5    PRY         Odd/even parity select bit, PRY
          b6    PRYE        Parity enable bit, PRYE
          b7    IOPOL       TxD, RxD I/O polarity reverse bit */

    /* clear UART0 receive buffer by reading */
    u0tb = u0rb;
    /* clear UART0 transmit buffer */
    u0tb = 0;

    /* Enable UART0 receive interrupt, priority level 4 */
    s0ric = 0x04;

    /* UART0 transmit/receive control register 1 */
    /* enable transmit and receive */
    u0c1 = 0x05;
        /*  00000101    enable transmit and receive
        b0      TE          Transmit enable bit
        b1      TI          Transmit buffer empty flag
        b2      RE          Receive enable bit
        b3      RI          Receive complete flag
        b5:b4               Reserved, set to 0
        b6      UOLCH       Data logic select bit
        b7      UOERE       Error signal output enable bit */
}

#pragma SECTION program ram_based_prg

#define  COMM_RX_BUF_SIZE      2048

typedef struct {
    unsigned short     RingBufRxCtr;                /* Number of characters in the Rx ring buffer              */
    unsigned short     *RingBufRxInPtr;              /* Pointer to where next character will be inserted        */
    unsigned short     *RingBufRxOutPtr;             /* Pointer from where next character will be extracted */
    unsigned short      RingBufRx[COMM_RX_BUF_SIZE]; /* Ring buffer character storage (Rx)                 */
  } COMM_RING_BUF;


COMM_RING_BUF  UART0Buf;

void  CommInit (void)
{
    COMM_RING_BUF *pbuf;

    pbuf                  = &UART0Buf;                     /* Initialize the ring buffer for COMM1     */
    pbuf->RingBufRxCtr    = 0;
    pbuf->RingBufRxInPtr  = &pbuf->RingBufRx[0];
    pbuf->RingBufRxOutPtr = &pbuf->RingBufRx[0];
}

unsigned char  CommIsEmpty ()
{
    unsigned char        empty;
    COMM_RING_BUF *pbuf;

    pbuf = &UART0Buf;

    if (pbuf->RingBufRxCtr > 0) {                          /* See if buffer is empty                   */
        empty = 0;                                     /* Buffer is NOT empty                      */
    } else {
        empty = 1;                                      /* Buffer is empty                          */
    }
    return (empty);
}

unsigned short  CommGetChar ()
{
	unsigned short          c;

	COMM_RING_BUF *pbuf;
    
	pbuf = &UART0Buf;

	{

		pbuf->RingBufRxCtr--;                              /* Yes, decrement character count           */
		c = *pbuf->RingBufRxOutPtr++;                      /* Get character from buffer                */
		if (pbuf->RingBufRxOutPtr == &pbuf->RingBufRx[COMM_RX_BUF_SIZE]) 
		{     /* Wrap OUT pointer     */
			pbuf->RingBufRxOutPtr = &pbuf->RingBufRx[0];
		}

		return (c);
	}
}

void  CommPutRxChar (unsigned short c)
{
    COMM_RING_BUF *pbuf;

    pbuf = &UART0Buf;

    if (pbuf->RingBufRxCtr < COMM_RX_BUF_SIZE) {           /* See if buffer is full                    */
        pbuf->RingBufRxCtr++;                              /* No, increment character count            */
        *pbuf->RingBufRxInPtr++ = c;                       /* Put character into buffer                */
        if (pbuf->RingBufRxInPtr == &pbuf->RingBufRx[COMM_RX_BUF_SIZE]) { /* Wrap IN pointer           */
            pbuf->RingBufRxInPtr = &pbuf->RingBufRx[0];
        }
    }
}

void  u0rec_handler (void)
{
	unsigned short   c;
	while(ri_u0c1 == 0)
		;
	c = u0rb;
	CommPutRxChar(c);
}

/****************************************/
/*    ClearSCITxFlag function           */
/****************************************/
static void ClearSCITxFlag( void )
{
		// cleared by writing to the U0TB lower byte
}

/****************************************/
/*    RxByteWaiting function			*/
/****************************************/
static unsigned char RxByteWaiting ( void )
{
	//
	// returns 1 - if the byte is waiting
	// returns 0 - if no byte is waiting
	//
	
	unsigned char tmp;
	
	if( ri_u0c1 == 0 )
	{
		tmp = 0;
	}
	else
	{
		tmp = 1;
	}

	return tmp;
}

/****************************************/
/*    TxByteEmpty function				*/
/****************************************/
static unsigned char TxByteEmpty ( void )
{
	//
	// returns 1 - if the transmit register is empty
	// returns 0 - if the transmit register is not empty
	//
	
	unsigned char tmp;
	
	if( ti_u0c1 == 0 )
	{
		tmp = 0;
	}
	else
	{
		tmp = 1;
	}
	
	return tmp;
}

/****************************************/
/*    TxByteLoad function				*/
/****************************************/
static void TxByteLoad( unsigned char b )
{
		u0tbl = b;
}

/****************************************/
/*    SendByte function	    			*/
/****************************************/
void SendByte ( unsigned char b )
{
	while( TxByteEmpty() == 0 );
	TxByteLoad( b );
	ClearSCITxFlag();
}

/****************************************/
/*    SendString function   			*/
/****************************************/
void SendString ( char far *str )
{
	// sends string until NUL terminator is reached
	
	unsigned short us;

	us = 0;
	while ( str[us] != 0 )
	{
		SendByte ( (unsigned char) str[us] );
		us++;
	}
}

/****************************************/
/*    GetByte function       			*/
/****************************************/
unsigned short GetByte ( unsigned long timeout )
{
	//	timeout = time in ms for which to timeout the data reception
	//
	//	returns a 16-bit value
	//	upper (msb) byte contains status info
	//	lower (lsb) byte contains the data received from the SCI channel
	//
	//	status:
	//	OK
	//	ERROR
	//	TIMEOUT
	//
	
	union union_c2s c2s;	
	unsigned long tick_count;
	
	tick_count = timeout / MS_PER_TIMER_COMPARE_MATCH;
	
	StartDelayTimer();
	
	// wait for a byte to arrive
	while ( ( CommIsEmpty() == 1 ) && (tick_count) )
	{
		if ( GetDelayTimerStatus() )
		{
			StopDelayTimer();
			if ( --tick_count )
			{
				StartDelayTimer();
			}
		}
	}
	
	if ( CommIsEmpty() == 0 )
	{

	// read error flags and data
		c2s.us = CommGetChar();
		
		// check for errors
		if( c2s.uc[1] & 0x80 )
		{
			// Rx error
			//
			// check for parity error
			if( c2s.uc[1] & 0x40 )
			{
				// parity error
			}
			// check for framing error
			if( c2s.uc[1] & 0x20 )
			{
				// framing error
			}
			// check for overrun error
			if( c2s.uc[1] & 0x10 )
			{
				// overrun error
				// clearing the overrun error flag is a special case
				//
				// clear Tx enable

				re_u0c1 = 0;
				// set Tx enable

				re_u0c1 = 1;
			}
			
			c2s.uc[ 0 ] = ERROR;
		}
		else
		{
			// no Rx error
			c2s.uc[ 1 ] = c2s.uc[ 0 ];
			c2s.uc[ 0 ] = OK;
		}		

//		c2s.uc[ 1 ] = CommGetChar();
//		c2s.uc[ 0 ] = OK;
	}
	else
	{
		c2s.uc[0] = TIMEOUT;
	}
	
	return (c2s.us);
}

/****************************************/
/*    PurgeComms function       		*/
/****************************************/
void PurgeComms ( unsigned long timeout )
{
	union union_c2s c2s;
	
	do {
		c2s.us = GetByte( timeout );
	} while( (c2s.uc[0] != TIMEOUT) && (c2s.uc[0] != ERROR) );

}
